#include <stdint.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#ifdef ignore
#undef ignore
#endif
#include <sstream>
#include "common.h"
#include "BbuManager.h"
#include "eutranManager.h"
#include "eutranCtrl.h"
#include "NmmToX86Protocol.h"
#include "NmmToCtrlBoardMessage.h"
#include "OamMessageProtocol.h"
#include "EutranConfigData.h"
#include "ProcedureCtrl.h"
#include "SnifferManager.h"
#include "EutranTcpReceiver.h"

uint8_t BandData::bandTable_[65536];

BandData::BandData()
{
    memset(bandTable_, 0xff, sizeof(bandTable_));
    
    for(uint32_t i=0; i<=0xffff; i++)
    {
        if( i>=0 && i<=599 )
        {
            bandTable_[i] = 1;
        }
        else if( i>=600 && i<=1199 )
        {
            bandTable_[i] = 2;
        }
        else if( i>=1200 && i<=1949 )
        {
            bandTable_[i] = 3;
        }
        else if( i>=1950 && i<=2399 )
        {
            bandTable_[i] = 4;
        }
        else if( i>=2400 && i<=2649 )
        {
            bandTable_[i] = 5;
        }
        else if( i>=2650 && i<=2749 )
        {
            bandTable_[i] = 6;
        }
        else if( i>=2750 && i<=3449 )
        {
            bandTable_[i] = 7;
        }
        else if( i>=3450 && i<=3799 )
        {
            bandTable_[i] = 8;
        } 
        else if( i>=3800 && i<=4149 )
        {
            bandTable_[i] = 9;
        }
        else if( i>=4150 && i<=4749 )
        {
            bandTable_[i] = 10;
        }
        else if( i>=4750 && i<=4949 )
        {
            bandTable_[i] = 11;
        }
        else if( i>=5010 && i<=5179 )
        {
            bandTable_[i] = 12;
        }
        else if( i>=5180 && i<=5279 )
        {
            bandTable_[i] = 13;
        }
        else if( i>=5280 && i<=5379 )
        {
            bandTable_[i] = 14;
        }
        else if( i>=5730 && i<=5849 )
        {
            bandTable_[i] = 17;
        }
        else if( i>=5850 && i<=5999 )
        {
            bandTable_[i] = 18;
        }
        else if( i>=6000 && i<=6149 )
        {
            bandTable_[i] = 19;
        }
        else if( i>=6150 && i<=6449 )
        {
            bandTable_[i] = 20;
        }
        else if( i>=6450 && i<=6599 )
        {
            bandTable_[i] = 21;
        }
        else if( i>=6600 && i<=7399 )
        {
            bandTable_[i] = 22;
        }
        else if( i>=7500 && i<=7699 )
        {
            bandTable_[i] = 23;
        }
        else if( i>=7700 && i<=8039 )
        {
            bandTable_[i] = 24;
        }
        else if( i>=8040 && i<=8689 )
        {
            bandTable_[i] = 25;
        }
        else if( i>=8690 && i<=9039 )
        {
            bandTable_[i] = 26;
        }
        else if( i>=9040 && i<=9209 )
        {
            bandTable_[i] = 27;
        }
        else if( i>=9210 && i<=9659 )
        {
            bandTable_[i] = 28;
        }
        else if( i>=9660 && i<=9769 )
        {
            bandTable_[i] = 29;
        }
        else if( i>=9770 && i<=9869 )
        {
            bandTable_[i] = 30;
        }
        else if( i>=9870 && i<=9919 )
        {
            bandTable_[i] = 31;
        }
        else if( i>=9920 && i<=10359 )
        {
            bandTable_[i] = 32;
        }
        else if( i>=36000 && i<=36199 )
        {
            bandTable_[i] = 33;
        }
        else if( i>=36200 && i<=36349 )
        {
            bandTable_[i] = 34;
        }
        else if( i>=36350 && i<=36949 )
        {
            bandTable_[i] = 35;
        }
        else if( i>=36950 && i<=37549 )
        {
            bandTable_[i] = 36;
        }
        else if( i>=37550 && i<=37749 )
        {
            bandTable_[i] = 37;
        }
        else if( i>=37750 && i<=38249 )
        {
            bandTable_[i] = 38;
        }
        else if( i>=38250 && i<=38649 )
        {
            bandTable_[i] = 39;
        }
        else if( i>=38650 && i<=39649 )
        {
            bandTable_[i] = 40;
        }
        else if( i>=39650 && i<=41589 )
        {
            bandTable_[i] = 41;
        }
        else if( i>=41590 && i<=43589 )
        {
            bandTable_[i] = 42;
        }
        else if( i>=43590 && i<=45589 )
        {
            bandTable_[i] = 43;
        }
        else if( i>=45590 && i<=46589 )
        {
            bandTable_[i] = 44;
        }
    }
}

BandData* BandData::instance()
{
    static BandData instance_;
    return &instance_;
}

bool BandData::getArfcnRangeFromBand(uint8_t band, uint16_t& lowerArfcn, uint16_t& upperArfcn)
{
    if( band==9 )
    {
        lowerArfcn = 3800;
        upperArfcn = 4149;
    }
    else if( band==38 )
    {
        lowerArfcn = 37750;
        upperArfcn = 38249;
    }
    else if( band==39 )
    {
        lowerArfcn = 38250;
        upperArfcn = 38649;
    }
    else if( band==40 )
    {
        lowerArfcn = 38650;
        upperArfcn = 39649;
    }
    else if( band==41 )
    {
        lowerArfcn = 39650;
        upperArfcn = 41589;
    }
    else
    {
        return false;
    }
    return true;
}

/*
BandCap::BandCap(uint32_t mask):
capacities_(mask)
{
}

bool BandCap::isSupported(uint32_t mask)
{
    return (capacities_ & mask)!=0;
}

void BandCap::addBand(uint8_t band)
{
    if( band==9 )
    {
        capacities_ |= BAND9;
    }
    else if( band==38 )
    {
        capacities_ |= BAND38;
    }
    else if( band==39 )
    {
        capacities_ |= BAND39;
    }
    else if( band==40 )
    {
        capacities_ |= BAND40;
    }
}

uint32_t BandCap::getBandMaskCodeFromEarfcn(uint16_t earfcn)
{
    uint8_t band = BandDataPtr->getBandFromEarfcn(earfcn);
    if( band==9 )
    {
        return BAND9;
    }
    else if( band==38 )
    {
        return BAND38;
    }
    else if( band==39 )
    {
        return BAND39;
    }
    else if( band==40 )
    {
        return BAND40;
    }
    return 0;
}*/

BbuInstance::BbuInstance():
fd_(-1),
slotId_(0),
isActive_(false),
isHearbeatRecv_(false),
supportMode_(NUM_OF_LTE_DUPLEX_MODE),
operator_(NUM_OF_CHINA_TELE_OPER),
seqNo_(0),
stateCode_(BBU_INACTIVE)
{
    memset(&peerAddr_, 0, sizeof(peerAddr_));
    peerAddr_.sin_family = AF_INET;
    peerAddr_.sin_port = htons(31790);

    fd_ = socket(AF_INET, SOCK_DGRAM, 0);
    if( fd_==-1 )
    {
        EMLogError("Fail to create socket");
        throw std::exception();
    }
}

/*
BbuInstance::BbuInstance(const char* address, uint16_t slotId) throw (std::exception):
fd_(-1),
slotId_(slotId),
isActive_(false),
isHearbeatRecv_(false),
supportMode_(NUM_OF_LTE_DUPLEX_MODE),
operator_(NUM_OF_CHINA_TELE_OPER),
bandSupported_(0)
{
    memset(&peerAddr_, 0, sizeof(peerAddr_));
    peerAddr_.sin_family = AF_INET;
    if( address!=NULL )
    {
        peerAddr_.sin_addr.s_addr = inet_addr(address);
    }
    else
    {
        peerAddr_.sin_addr.s_addr = inet_addr("192.168.1.211");
    }

    char* envString = getenv("nmmport");
    if( envString!=NULL )
    {
        peerAddr_.sin_port = htons(atoi(envString));
    }
    else
    {
        peerAddr_.sin_port = htons(31790);
    }

    if( fd_!=-1 )
    {
        close(fd_);
    }
    
    fd_ = socket(AF_INET, SOCK_DGRAM, 0);
    if( fd_==-1 )
    {
        EMLogError("Fail to create socket");
        throw std::exception();
    }
}*/

uint32_t BbuInstance::getSlotId()
{
    return slotId_;
}

BbuInstance& BbuInstance::setSlotId(uint8_t slotId)
{
    slotId_ = slotId;
    return *this;
}

BbuInstance& BbuInstance::setPeerAddress(const char* addr, uint16_t port)
{
    if( addr!=NULL )
    {
        peerAddr_.sin_addr.s_addr = inet_addr(addr);
    }
    else
    {
        peerAddr_.sin_addr.s_addr = inet_addr("192.168.1.1");
    }

    peerAddr_.sin_port = htons(port);

    return *this;
}

LteDuplexMode BbuInstance::getDuplexMode()
{
    return supportMode_;
}

BbuInstance& BbuInstance::setDuplexMode(LteDuplexMode mode)
{
    supportMode_ = mode;
    return *this;
}

ChinaTelecomOperator BbuInstance::getTeleOperator()
{
    return operator_;
}

BbuInstance& BbuInstance::setTeleOperator(ChinaTelecomOperator ope)
{
    operator_ = ope;
    return *this;
}

bool BbuInstance::IsBandSupported(uint8_t band)
{
    return bandSupported_.count(band)!=0;
}

BbuInstance& BbuInstance::addBandSupported(uint8_t band)
{
    bandSupported_.insert(band);
    return *this;
}

void BbuInstance::getSupportedBands(std::set<uint8_t>& bands)
{
    bands.clear();
    bands = bandSupported_;
}

bool BbuInstance::isHearBeatAckRev()
{
    return isHearbeatRecv_;
}

BbuInstance& BbuInstance::setHearBeatAckRecv(bool isRecv)
{
    isHearbeatRecv_ = isRecv;
    return *this;
}

uint32_t BbuInstance::getBbuIpAddress()
{
    return peerAddr_.sin_addr.s_addr;
}

bool BbuInstance::isActive()
{
    return isActive_;
}

bool BbuInstance::active()
{
    if( fd_==-1 )
    {
        EMLogError("UDP socket has not been initialized"); 
        return false;
    }

    isActive_ = true;
    isHearbeatRecv_ = true;
    
    return true;
}

void BbuInstance::deactive()
{
    StateReportProcedurePtr->reportState(*(BbuManagerPtr->getBbu(slotId_)), BBU_INACTIVE);
    isActive_ = false;
    isHearbeatRecv_ = false;
    seqNo_ = 0;
}

bool BbuInstance::sendMessage(TlvMessage& msg)
{
    uint8_t* msgBuf = NULL;
    uint32_t msgSize = 0;
    msg.getMsgBuffer(msgBuf, msgSize);

    return sendMessage(msgBuf, msgSize);
}

bool BbuInstance::sendMessage(uint8_t* msgBuf, uint32_t msgSize)
{
    if( msgBuf==NULL )
    {
        EMLogError("msgBuf is NULL");
        return false;
    }

    if( !isActive_ )
    {
        EMLogError("BBU[%d]: is not active", static_cast<uint32_t>(slotId_));
        return false;
    }

    std::stringstream ss;
    ss << "BBU[" << getSlotId() << "]: sendToEpcSim[addr:0x" << std::hex << peerAddr_.sin_addr.s_addr << "]: msg[0x" << std::hex << msgSize << " bytes]: ";
    for(uint32_t i=0; i<msgSize; i++)
    {
        ss << std::hex << "0x" << static_cast<uint32_t>(msgBuf[i]) << " ";
    }

    if( msgSize<2 || msgBuf[1]!=NmmToX86Protocol_Signal::HEARBEAT )
    {
        EMLogDebug("%s", ss.str().c_str());
    }
    
    if( fd_==-1 )
    {
        EMLogError("fd is not initialized");
        return false;
    }
    int send_rc = -1;
    socklen_t len = sizeof(peerAddr_);
    do
    {
        send_rc = ::sendto( fd_, msgBuf, msgSize, 0, (struct sockaddr *)&peerAddr_, len);
    }
    while ( (send_rc == -1) && (errno == EINTR) );

    if( send_rc>=0 )
    {
        return true;
    }

    EMLogError("fail to send message");
    return false;
}

uint32_t BbuInstance::allocSeqNo()
{
    return seqNo_++;
}

BbuStateCode BbuInstance::getState()
{
    return stateCode_;
}

BbuInstance& BbuInstance::setState(BbuStateCode state)
{
    if( stateCode_!=state )
    {
        EMLogInfo("BBU[%d]: change from state[%d] to state[%d]", getSlotId(), stateCode_, state);
        stateCode_ = state;
    }
    
    return *this;
}

bool BbuInstanceWithTcp::sendMessage(TlvMessage& msg)
{
    uint8_t* msgBuf = NULL;
    uint32_t msgSize = 0;
    msg.getMsgBuffer(msgBuf, msgSize);

    return sendMessage(msgBuf, msgSize);
}

bool BbuInstanceWithTcp::sendMessage(uint8_t* msgBuf, uint32_t msgSize)
{
    if( msgBuf==NULL )
    {
        EMLogError("msgBuf is NULL");
        return false;
    }

    if( !isActive_ )
    {
        EMLogError("BBU[%d]: is not active but send msgtype=%d", static_cast<uint32_t>(slotId_), static_cast<uint32_t>(msgBuf[1]));
        return false;
    }

    std::stringstream ss;
    ss << "BBU[" << getSlotId() << "]: sendToEpcSim[addr:0x" << std::hex << peerAddr_.sin_addr.s_addr << "]: msg[0x" << std::hex << msgSize << " bytes]: ";
    for(uint32_t i=0; i<msgSize; i++)
    {
        ss << std::hex << "0x" << static_cast<uint32_t>(msgBuf[i]) << " ";
    }

    if( msgSize<2 || msgBuf[1]!=NmmToX86Protocol_Signal::HEARBEAT )
    {
        EMLogInfo("%s", ss.str().c_str());
    }

    return EutranTcpReceiverPtr->sendMessage(peerAddr_.sin_addr.s_addr, msgBuf, msgSize);
}

void BbuInstance::changTeleOperator(int32_t OperatorType)
{
    if ( OperatorType == CHINA_UNICOM)
        operator_ = CHINA_UNICOM;
    else if (OperatorType == CHINA_TELECOM)
        operator_ = CHINA_TELECOM;

    EMLogInfo(" operator is [%d]", operator_); 
}



BbuCtrl::BbuCtrl():
pwerResetTimer_(600),
pwerResetHandler_(this, &BbuCtrl::powerReset),
pwerResetTimeoutTimer_(180),
pwerResetTimeoutHandler_(this, &BbuCtrl::pwerResetTimeout),
maxPwerResetNum_(3),
paCtrlTimeoutHandler_(this, &BbuCtrl::paCtrlTimeout),
paIsOn_(false),
paIsOpening_(false),
paCtrlTimer_(30),
isInitCfgComp_(false),
isWorking_(false),
isLocationEnable_(false),
isRegistered_(false),
isRecvImsi_(false),
workingDlArfcn_(0),
workingUlArfcn_(0),
workingPci_(0),
workingTac_(0),
isWorkingMeasEnable_(false),
isTxPwerPresent_(false),
txPwer_(0)
{
}

void BbuCtrl::processInitNotification2(NmmToX86Protocol_InitNotification& initNoti)
{
    CtrlBoardMsg::InitNotification notification;

    if( !initNoti.unpack(notification.band_, notification.duplexMode_) )
    {
        EMLogError("Fail to unpack InitNotification ");
        return;
    }

    EMLogInfo("process InitNotification, band=%d, duplexMode=%d", static_cast<uint32_t>(notification.band_), static_cast<uint32_t>(notification.duplexMode_));

    if( 0!=(notification.band_ & CtrlBoardMsg::BAND9_MASK))
    {
        if( !instanceData_.IsBandSupported(9) )
        {
            EMLogWarning("Band9 is not compatible with configuration");
        }
        instanceData_.addBandSupported(9);
    }

    if( 0!=(notification.band_ & CtrlBoardMsg::BAND38_MASK))
    {
        if( !instanceData_.IsBandSupported(38) )
        {
            EMLogWarning("Band38 is not compatible with configuration");
        }
        instanceData_.addBandSupported(38);
    }

    if( 0!=(notification.band_ & CtrlBoardMsg::BAND39_MASK))
    {
        if( !instanceData_.IsBandSupported(39) )
        {
            EMLogWarning("Band39 is not compatible with configuration");
        }
        instanceData_.addBandSupported(39);
    }

    if( 0!=(notification.band_ & CtrlBoardMsg::BAND40_MASK))
    {
        if( !instanceData_.IsBandSupported(40) )
        {
            EMLogWarning("Band40 is not compatible with configuration");
        }
        instanceData_.addBandSupported(40);
    }

    if( notification.duplexMode_!=instanceData_.getDuplexMode() )
    {
        EMLogError("Duplex mode received[%d] is not compatible with configuration[%d]", notification.duplexMode_, instanceData_.getDuplexMode());
        return;
    }

    instanceData_.active();

    buildAndSendSnifferReset();
    buildAndSendTimeSync();
}

void BbuCtrl::processHBAck(NmmToX86Protocol_HeartBeatAck& ack)
{
    EMLogDebug("BBU[%d]: process hb ack", getInstance().getSlotId());
    instanceData_.setHearBeatAckRecv(true);
}

bool BbuCtrl::sendRtParaCfg(OamMessageProtocol_RunTimeParaCfg& cfg)
{
    cfg.packSeqNum(instanceData_.allocSeqNo());
    return instanceData_.sendMessage(cfg.getMessage());
}

bool BbuCtrl::buildAndSendUeIdFilter(bool enable, uint32_t* timer)
{
    OamMessageProtocol_UeIdFilterSwitchCfg oamMsg;
    oamMsg.packSeqNum(instanceData_.allocSeqNo());
    oamMsg.pack(enable, timer);
    return instanceData_.sendMessage(oamMsg.getMessage());
}

bool BbuCtrl::buildAndSendStdTxPowerDbGet()
{
    OamMessageProtocol_TxPowerDbmStdGet oamMsg;
    oamMsg.packSeqNum(instanceData_.allocSeqNo());
    return instanceData_.sendMessage(oamMsg.getMessage());
}

bool BbuCtrl::buildAndSendStdTxPowerGet()
{
    OamMessageProtocol_TxPowerStdGet oamMsg;
    oamMsg.packSeqNum(instanceData_.allocSeqNo());
    return instanceData_.sendMessage(oamMsg.getMessage());
}

bool BbuCtrl::buildAndSendStdTxPower(uint8_t txPwer)
{
    OamMessageProtocol_TxPowerStdCfg oamMsg;
    oamMsg.packSeqNum(instanceData_.allocSeqNo());
    oamMsg.pack(txPwer);
    return instanceData_.sendMessage(oamMsg.getMessage());
}

bool BbuCtrl::buildAndSendInitCfg()
{
    EMLogInfo("BBU[%d]: Band width is %d", getInstance().getSlotId(), EutranConfigDataPtr->getBandWidth(getInstance().getSlotId()));
    EMLogInfo("GPS time delay is %d", EutranConfigDataPtr->getGpsDelay(getInstance().getSlotId()));
    EMLogInfo("Sync mode is %d", EutranConfigDataPtr->getSyncMode(getInstance().getSlotId()));
    EMLogInfo("Is save FS is %d", EutranConfigDataPtr->getIsSaveFS(getInstance().getSlotId()));
    EMLogInfo("Working band is %d", static_cast<uint32_t>(EutranConfigDataPtr->getWorkingBand(getInstance().getSlotId())));
    EMLogInfo("Working mode is %d", static_cast<uint32_t>(EutranConfigDataPtr->getWorkingMode(getInstance().getSlotId())));

    uint8_t bw = EutranConfigDataPtr->getBandWidth(getInstance().getSlotId());
    
    OamMessageProtocol_InitConfig initCfg;
    if( bw==10 )
    {
        initCfg.packBandWidth(0);
    }
    else if( bw==20 )
    {
        initCfg.packBandWidth(1);
    }
    else
    {
        initCfg.packBandWidth(2);
    }
    initCfg.packTimeDelay(EutranConfigDataPtr->getGpsDelay(getInstance().getSlotId()));
    initCfg.packSyncMode(EutranConfigDataPtr->getSyncMode(getInstance().getSlotId()));
    initCfg.packSeqNum(instanceData_.allocSeqNo());
    initCfg.packIsSaveFS(EutranConfigDataPtr->getIsSaveFS(getInstance().getSlotId()));
    initCfg.packWorkingBand(EutranConfigDataPtr->getWorkingBand(getInstance().getSlotId()));
    initCfg.packWorkingMode(EutranConfigDataPtr->getWorkingMode(getInstance().getSlotId()));

    return instanceData_.sendMessage(initCfg.getMessage());
}


bool BbuCtrl::buildAndSendMinRxLev()
{
    EMLogInfo("BBU[%d]: minRxLev is %d", getInstance().getSlotId(), EutranConfigDataPtr->getMinRxLev(getInstance().getSlotId()));
    EMLogInfo("BBU[%d]: minRxLevOffset is %d", getInstance().getSlotId(), static_cast<uint8_t>(EutranConfigDataPtr->getMinRxLevOffset(getInstance().getSlotId())));

    
    OamMessageProtocol_RxLevMinCfg rxLevMinCfg;
    rxLevMinCfg.pack(EutranConfigDataPtr->getMinRxLev(getInstance().getSlotId()), EutranConfigDataPtr->getMinRxLevOffset(getInstance().getSlotId()));
    rxLevMinCfg.packSeqNum(instanceData_.allocSeqNo());
    return instanceData_.sendMessage(rxLevMinCfg.getMessage());
}

bool BbuCtrl::buildAndSendSnifferReset()
{
    NmmToX86Protocol_SnifferReset reset;
    reset.packSeqNum(instanceData_.allocSeqNo());

    return instanceData_.sendMessage(reset.getMessage());
}

bool BbuCtrl::buildAndSendTimeSync()
{
    OamMessageProtocol_SysTime timeSync;
    timeSync.packSeqNum(instanceData_.allocSeqNo());
    timeSync.pack(time(NULL));

    return instanceData_.sendMessage(timeSync.getMessage());
}

bool BbuCtrl::buildAndSendSnifferStatusReq()
{
    NmmToX86Protocol_NmmStatusReq req;
    req.packSeqNum(instanceData_.allocSeqNo());
    return instanceData_.sendMessage(req.getMessage());
}

bool BbuCtrl::buildAndSendSysTimeSync()
{
    OamMessageProtocol_SysTime sysTime;

    uint64_t t = time(NULL);
    sysTime.packSeqNum(instanceData_.allocSeqNo());
    sysTime.pack(t);

    return instanceData_.sendMessage(sysTime.getMessage());
}

bool BbuCtrl::buildAndSendTxPowerDb(int8_t db)
{
    OamMessageProtocol_TxPowerDbmConfig dbmCfgMsg;
    dbmCfgMsg.packSeqNum(instanceData_.allocSeqNo());
    
    dbmCfgMsg.pack(db);

    return instanceData_.sendMessage(dbmCfgMsg.getMessage());
}

bool BbuCtrl::buildAndSendRxPower(uint8_t rxPwer)
{
    OamMessageProtocol_TxPower txPowerMsg;
    txPowerMsg.packSeqNum(instanceData_.allocSeqNo());
    
    txPowerMsg.pack(NULL, &rxPwer);

    return instanceData_.sendMessage(txPowerMsg.getMessage());
}

bool BbuCtrl::buildAndSendSoftwareVerReq()
{
    OamMessageProtocol_VersionReq verReqMsg;
    verReqMsg.packSeqNum(instanceData_.allocSeqNo());

    return instanceData_.sendMessage(verReqMsg.getMessage());
}

bool BbuCtrl::buildAndSendBbuStateReq()
{
    OamMessageProtocol_SysStatusReq req;

    req.packSeqNum(instanceData_.allocSeqNo());

    return instanceData_.sendMessage(req.getMessage());
}

bool BbuCtrl::buildAndSendRebootReq(std::string& desc)
{
    OamMessageProtocol_EquipReset reset;
    reset.packSeqNum(instanceData_.allocSeqNo());
    reset.pack(desc);

    return instanceData_.sendMessage(reset.getMessage());
}

bool BbuCtrl::buildAndSendSyncModeSetting(uint8_t modeCode)
{
    OamMessageProtocol_SyncMode syncMode;
    syncMode.packSeqNum(instanceData_.allocSeqNo());
    syncMode.pack(modeCode);

    return instanceData_.sendMessage(syncMode.getMessage());
    
}

bool BbuCtrl::buildAndSendSyncStateReq()
{
    OamMessageProtocol_SyncStatusReq req;
    req.packSeqNum(instanceData_.allocSeqNo());

    return instanceData_.sendMessage(req.getMessage());
}

bool BbuCtrl::buildAndSendGpsStateReq()
{
    OamMessageProtocol_GpsInfoReq req;

    req.packSeqNum(instanceData_.allocSeqNo());

    return instanceData_.sendMessage(req.getMessage());
}

bool BbuCtrl::buildAndSendUpgradeReq(std::string& ipAddr, std::string& fileName, std::string& md5, std::string& userName, std::string& passwd, uint8_t downMode)
{
    OamMessageProtocol_SoftwareUpgradReq req;
    req.pack(ipAddr, fileName, reinterpret_cast<uint8_t*>(const_cast<char*>(md5.c_str())), md5.length(), downMode);
    req.packSeqNum(instanceData_.allocSeqNo());
    return instanceData_.sendMessage(req.getMessage());
}

bool BbuCtrl::buidlAndSendLocModeSetting(bool isEnable, std::vector<std::string>& imsiList)
{
    OamMessageProtocol_LocationModeSetting locModeSetting;
    locModeSetting.packSeqNum(instanceData_.allocSeqNo());

    if( isEnable )
    {
        locModeSetting.pack(isEnable, &imsiList);
    }
    else
    {
        locModeSetting.pack(isEnable, NULL);
    }
    return instanceData_.sendMessage(locModeSetting.getMessage());
}

bool BbuCtrl::buildAndSendUeRedire(bool isEnable, uint8_t* ranType, uint8_t* band, std::vector<uint16_t>* arfcnList, std::vector<std::string>* imsiList)
{
    NmmToX86Protocol_UeRedirect msg;
    msg.packSeqNum(instanceData_.allocSeqNo());

    msg.pack(isEnable, ranType, band, arfcnList, imsiList);
    return instanceData_.sendMessage(msg.getMessage());
}

bool BbuCtrl::buildAndSendScanReq()
{
    NmmToX86Protocol_LteScanReq msg;
    msg.packSeqNum(instanceData_.allocSeqNo());

    return instanceData_.sendMessage(msg.getMessage());
}

bool BbuCtrl::buildAndSendInterferenceEnable(bool isEnable)
{
    OamMessageProtocol_InterferenceEnable msg;
    msg.packSeqNum(instanceData_.allocSeqNo());
    msg.pack(isEnable);
    
    return instanceData_.sendMessage(msg.getMessage());
}

bool BbuCtrl::buildAndSendScanMode(std::vector<uint16_t>& dlArfcnList, uint32_t sec)
{
    OamMessageProtocol_SetScanMode msg;
    msg.packSeqNum(instanceData_.allocSeqNo());

    msg.pack(&dlArfcnList, sec);
    return instanceData_.sendMessage(msg.getMessage());
}

BbuInstance& BbuCtrl::getInstance()
{
    return instanceData_;
}

BbuCtrl& BbuCtrl::connEstablish()
{
    setInitCfgComp(false);
    isWorking_ = false;
    return *this;
}

BbuCtrl& BbuCtrl::setInitCfgComp(bool isDone)
{
    isInitCfgComp_ = isDone;
    
    return *this;
}

BbuCtrl& BbuCtrl::setWorking(bool isWk)
{
    isWorking_ = isWk;
    return *this;
}

uint16_t BbuCtrl::getWorkingDlArfcn()
{
    return workingDlArfcn_;
}

uint16_t BbuCtrl::getWorkingUlArfcn()
{
    return workingUlArfcn_;
}

void BbuCtrl::setWorkingDlArfcn(uint16_t dlArfcn)
{
    workingDlArfcn_ = dlArfcn;

}

uint16_t BbuCtrl::getWorkingPci()
{
    return workingPci_;
}

uint16_t BbuCtrl::getWorkingTac()
{
    return workingTac_;
}

std::vector<uint32_t>& BbuCtrl::getWorkingPlmnList()
{
    return workingPlmnList_;
}

bool BbuCtrl::getTxPower(int16_t& txPwer)
{
    if( isTxPwerPresent_ )
    {
        txPwer = txPwer_;
        return true;
    }

    return false;
}

std::vector<uint16_t>& BbuCtrl::getSnifferArfcn()
{
    return snfArfcn_;
}

void BbuCtrl::setSnifferArfcn(std::vector<uint16_t>& arfcnRange)
{
    snfArfcn_ = arfcnRange;
}

void BbuCtrl::setWorkingPlmnList(std::vector<uint32_t> &plmnList)
{
    workingPlmnList_ = plmnList;
}


bool BbuCtrl::getWorkingMeasEnable()
{
    return isWorkingMeasEnable_;
}

BbuCtrl& BbuCtrl::setLocationEnable(bool isEnable)
{
    EMLogInfo("BBU[%d]: location enable[%d]", getInstance().getSlotId(), isEnable);
    isLocationEnable_ = isEnable;
    return *this;
}

BbuCtrl& BbuCtrl::setWorkingUlArfcn(uint16_t ulArfcn)
{
    EMLogInfo("BBU[%d]: set working ULARFCN: %d", getInstance().getSlotId(), ulArfcn);

    workingUlArfcn_ = ulArfcn;
    return *this;
}

BbuCtrl& BbuCtrl::setWorkingCellInfo(uint16_t dlArfcn, uint16_t ulArfcn, uint16_t pci, uint16_t tac, 
                                                                 const std::vector<uint32_t>& plmnList, int16_t* txPwerPtr,  bool isMeasEnable)
{
    workingDlArfcn_ = dlArfcn;
    workingUlArfcn_ = ulArfcn;
    workingPci_ = pci;
    workingTac_ = tac;
    workingPlmnList_ = plmnList;
    isWorkingMeasEnable_ = isMeasEnable;

    isTxPwerPresent_ = false;
    if( txPwerPtr!=NULL )
    {
        isTxPwerPresent_ = true;
        txPwer_ = *txPwerPtr;
    }

    for(size_t i=0; i<plmnList.size(); i++)
    {
        EMLogInfo("BBU[%d]: set working plmn: %d\n", getInstance().getSlotId(), plmnList[i]);
    }
    return *this;
}

bool BbuCtrl::isLocationEnable()
{
    return isLocationEnable_;
}

bool BbuCtrl::isInitCfgComplete()
{
    return isInitCfgComp_;
}

bool BbuCtrl::isWorking()
{
    return isWorking_;
}

void BbuCtrl::indicateDeactive(bool isCloseConn)
{
    EMLogInfo("BBU[%d]: indicate deactive", getInstance().getSlotId());

    workingPlmnList_.clear();
    getInstance().deactive();
    setInitCfgComp(false);
    setWorking(false);
    setLocationEnable(false);
    setRecvImsi(false);
    isWorkingMeasEnable_ = false;
    isTxPwerPresent_ = false;
    handleCtrlPA(false, BbuCtrl::REBOOT);
    SnifferMgrPtr->indicateBbuDeactive(*this);
    

    if( !EutranTimerPtr->queue(pwerResetTimer_, &pwerResetHandler_) )
    {
        EMLogError("BBU[%d]: Fail to start pwerResetTimer");
    }
    if( isCloseConn )
    {
#ifdef USE_TCP_CONN
    EutranTcpReceiverPtr->shutdown(getInstance().getBbuIpAddress());
#endif
    }
}

void BbuCtrl::indicateAactive()
{
    EMLogInfo("BBU[%d]: indicate active", getInstance().getSlotId());
    getInstance().active();
    SnifferMgrPtr->indicateBbuActive(*this);

    EutranTimerPtr->dequeue(&pwerResetHandler_);
    EutranTimerPtr->dequeue(&pwerResetTimeoutHandler_);

    maxPwerResetNum_ = 3;
}

void BbuCtrl::powerReset()
{
    EMLogInfo("BBU[%d]: power reset[%d]", getInstance().getSlotId(), maxPwerResetNum_);
    maxPwerResetNum_--;
    EutranMgrPtr->bbuPowerReset(getInstance().getSlotId());

    if( !EutranTimerPtr->queue(pwerResetTimeoutTimer_, &pwerResetTimeoutHandler_) )
    {
        EMLogError("BBU[%d]: Fail to start pwerResetTimer", getInstance().getSlotId());
    }
}

void BbuCtrl::pwerResetTimeout()
{
    if( maxPwerResetNum_<=0 )
    {
        EMLogInfo("BBU[%d]: MAX power reset num reaches", getInstance().getSlotId());
        std::stringstream ss;
        ss << "BBU[" << getInstance().getSlotId() << "] baseband lost connction, hard reset no use";
        saveImportantLog(ss.str().c_str());
        BbuManagerPtr->reportBbuLost(getInstance().getSlotId());
        return;
    }

    maxPwerResetNum_--;
    EutranMgrPtr->bbuPowerReset(getInstance().getSlotId());

    if( !EutranTimerPtr->queue(pwerResetTimeoutTimer_, &pwerResetTimeoutHandler_) )
    {
        EMLogError("BBU[%d]: Fail to start pwerResetTimer", getInstance().getSlotId());
    }
}

void BbuCtrl::registerBbu(uint8_t slotId)
{
    isRegistered_ = true;
    EMLogInfo("Slot-id[%d] is registered", static_cast<uint32_t>(slotId));
}

bool BbuCtrl::BbuIsRegisted()
{
    return isRegistered_;
}

void BbuCtrl::setRecvImsi(bool isRecv)
{
    isRecvImsi_ = isRecv;    
}

bool BbuCtrl::isRecvImsi()
{
    return isRecvImsi_;
}

uint8_t BbuCtrl::getPaId()
{
    uint8_t band = EutranConfigDataPtr->getWorkingBand(getInstance().getSlotId());
    uint8_t paId = 10;
    switch(band)
    {
        case 38:
            paId = 1;
            break;

        case 39:
            paId = 2;
            break;

        case 40:
            paId = 3;
            break;

        case 41:
            paId = 1;
            break;

        case 1:
            paId = 6;
            break;

        case 3:
            paId = 7;
            break;

        default:
            EMLogWarning("not support band in pa list");
            break;
    }
    return paId;
}

void BbuCtrl::handleCtrlPaResult(bool isOn)
{
    if (!isOn &&  paIsOpening_)
    {
        std::string desc = "main control board control restart";
        buildAndSendRebootReq(desc);
        EMLogWarning("do not handleType is change");
    }
    
    if (isOn == paIsOpening_)
    {
        paIsOn_ = isOn;
        if (paHandleType_ == DO_NOTHING)
        {
            EMLogNotice("BBU[%d] control pa success do nothing",  static_cast<uint32_t>(getInstance().getSlotId()));
        }
        else if (paHandleType_ == POWER_RESET)
        {
            EutranMgrPtr->bbuPowerReset(getInstance().getSlotId());
            EMLogNotice("BBU[%d] control pa success power reset ",  static_cast<uint32_t>(getInstance().getSlotId()));
        }
        else if (paHandleType_ == REBOOT)
        {
            EMLogNotice("BBU[%d] control pa success",  static_cast<uint32_t>(getInstance().getSlotId()));
            std::string desc = "main control board control restart";
            buildAndSendRebootReq(desc);
        }
        EutranTimerPtr->dequeue(&paCtrlTimeoutHandler_);
    }
    else
    {
        EMLogWarning("do not handleType is change");


    }
}

void BbuCtrl::handleCtrlPA(bool isOpening, uint8_t ctrlType)
{
    paHandleType_ = ctrlType;
    if ((isOpening == paIsOn_) && (isOpening == paIsOpening_))
    {
        if (paHandleType_ == DO_NOTHING)
        {
            EMLogNotice("BBU[%d] do not control pa because pa state is same",  static_cast<uint32_t>(getInstance().getSlotId()));
        }
        else if (paHandleType_ == POWER_RESET)
        {
            EutranMgrPtr->bbuPowerReset(getInstance().getSlotId());
            EMLogNotice("BBU[%d] do not control pa because pa state is same",  static_cast<uint32_t>(getInstance().getSlotId()));
        }
        else if (paHandleType_ == REBOOT)
        {
            EMLogNotice("BBU[%d] do not control pa because pa state is same",  static_cast<uint32_t>(getInstance().getSlotId()));
            std::string desc = "main control board control restart";
            buildAndSendRebootReq(desc);
        }
        return;
    }
    
    paIsOpening_ = isOpening;
    EutranMgrPtr->controlPA(getPaId(), paIsOpening_);
    maxPaCtrlNum_ = 2;
    if( !EutranTimerPtr->queue(paCtrlTimer_, &paCtrlTimeoutHandler_) )
    {
        EMLogError("BBU[%d]: Fail to queue paCtrlTimeoutHandler", getInstance().getSlotId());
    }


}

void BbuCtrl::paCtrlTimeout()
{
    if (maxPaCtrlNum_ <= 0)
    {
        EMLogError("BBU[%d]: contrl pa failed", static_cast<uint32_t>(getInstance().getSlotId()));
        if (paHandleType_ == DO_NOTHING)
        {
            EMLogNotice("BBU[%d] contrl pa failed but do nothing",  static_cast<uint32_t>(getInstance().getSlotId()));
        }
        else if (paHandleType_ == POWER_RESET)
        {
            EutranMgrPtr->bbuPowerReset(getInstance().getSlotId());
            EMLogNotice("BBU[%d] contrl pa failed and power reset bbu",  static_cast<uint32_t>(getInstance().getSlotId()));
        }
        else if (paHandleType_ == REBOOT)
        {
            EMLogNotice("BBU[%d] contrl pa failed and reboot bbu",  static_cast<uint32_t>(getInstance().getSlotId()));
            std::string desc = "main control board control restart";
            buildAndSendRebootReq(desc);
        }
        return;
    }
    maxPaCtrlNum_--;
    EutranMgrPtr->controlPA(getPaId(), paIsOpening_);
  
    if( !EutranTimerPtr->queue(paCtrlTimer_, &paCtrlTimeoutHandler_) )
    {
        EMLogError("BBU[%d]: Fail to queue paCtrlTimeoutHandler", getInstance().getSlotId());
    }

    
}


BbuManager::BbuManager():
sendHBTimer_(5),
sendHBHandler_(this, &BbuManager::sendHearBeat),
checkBbuAliveTimer_(25),
checkBbuAliveHandler_(this, &BbuManager::checkBbuAlive),
checkRecvImsiTimer_(7200),
checkRecvImsiHandler_(this, &BbuManager::checkRecvImsi),
isLocationMode_(false)
{
};

BbuManager* BbuManager::instance()
{
    static BbuManager instance_;
    return &instance_;
}

bool BbuManager::initialize()
{
    bbuCtrls_[0].instanceData_.setSlotId(1).setDuplexMode(TDD).setTeleOperator(CHINA_MOBILE).addBandSupported(38).setPeerAddress("192.168.178.211", 31790);
    bbuCtrls_[1].instanceData_.setSlotId(2).setDuplexMode(TDD).setTeleOperator(CHINA_MOBILE).addBandSupported(39).setPeerAddress("192.168.178.212", 31790);
    bbuCtrls_[2].instanceData_.setSlotId(3).setDuplexMode(TDD).setTeleOperator(CHINA_MOBILE).addBandSupported(40).setPeerAddress("192.168.178.213", 31790);
    bbuCtrls_[3].instanceData_.setSlotId(4).setDuplexMode(TDD).setTeleOperator(CHINA_TELECOM).addBandSupported(40).setPeerAddress("192.168.178.214", 31790);
    bbuCtrls_[4].instanceData_.setSlotId(5).setDuplexMode(TDD).setTeleOperator(CHINA_UNICOM).addBandSupported(40).setPeerAddress("192.168.178.215", 31790);
    bbuCtrls_[5].instanceData_.setSlotId(6).setDuplexMode(FDD).setTeleOperator(CHINA_TELECOM).addBandSupported(9).setPeerAddress("192.168.178.216", 31790);
    bbuCtrls_[6].instanceData_.setSlotId(7).setDuplexMode(FDD).setTeleOperator(CHINA_UNICOM).addBandSupported(9).setPeerAddress("192.168.178.217", 31790);
	locationEnable[TDD] = false;
	locationEnable[FDD] = false;
#ifndef USE_TCP_CONN
    EutranTimerPtr->queue(sendHBTimer_, &sendHBHandler_);
#endif
    EutranTimerPtr->queue(checkBbuAliveTimer_, &checkBbuAliveHandler_);
    EutranTimerPtr->queue(checkRecvImsiTimer_, &checkRecvImsiHandler_);   

    return true;
}

BbuCtrl* BbuManager::getBbu(uint8_t slotId)
{
    EMLogDebug("Get BBU from slotId[%d]", static_cast<uint32_t>(slotId));
    
    if( slotId>MAX_BBU_INSTANCES || slotId==0 )
    {
        return NULL;
    }
    return &bbuCtrls_[slotId-1];
}

BbuCtrl* BbuManager::getBbu(in_addr_t addr)
{
    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].instanceData_.peerAddr_.sin_addr.s_addr==addr )
        {
            return &bbuCtrls_[i];
        }
    }
    return NULL;
}

BbuCtrl* BbuManager::getBbu(uint8_t band, ChinaTelecomOperator oper)
{
    EMLogInfo("Get BBU from band[%d] and telecomOper[%d]", static_cast<uint32_t>(band), oper);
    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].instanceData_.bandSupported_.count(band)!=0 && bbuCtrls_[i].instanceData_.operator_==oper )
        {
            return &bbuCtrls_[i];
        }
    }
    return NULL;
}

void BbuManager::sendHearBeat()
{
    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].instanceData_.isActive() )
        {
            NmmToX86Protocol_HeartBeat hb;
            hb.packSeqNum(bbuCtrls_[i].instanceData_.allocSeqNo());
            bbuCtrls_[i].instanceData_.sendMessage(hb.getMessage());
        }
    }

    EutranTimerPtr->queue(sendHBTimer_, &sendHBHandler_);
}

void BbuManager::checkBbuAlive()
{
    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].instanceData_.isActive() )
        {
            if( !bbuCtrls_[i].instanceData_.isHearBeatAckRev() )
            {
                EMLogWarning("BBU[%d] is down", bbuCtrls_[i].instanceData_.getSlotId());
                bbuCtrls_[i].indicateDeactive();
            }
            else
            {
                bbuCtrls_[i].instanceData_.setHearBeatAckRecv(false);
            }
        }
    }
    EutranTimerPtr->queue(checkBbuAliveTimer_, &checkBbuAliveHandler_);
}

uint32_t BbuManager::getNoOfActivateBbu()
{
    uint32_t num = 0;
    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].instanceData_.isActive() )
        {
            num++;
        }
    }

    return num;
}

void BbuManager::getIdOfActiveBbus(std::set<uint32_t>& ids)
{
    ids.clear();

    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].instanceData_.isActive() )
        {
            ids.insert(bbuCtrls_[i].instanceData_.getSlotId());
        }
    }
}

bool BbuManager::isSlotIdValid(uint8_t slotId)
{
    if( slotId==0 || slotId>BbuManager::MAX_BBU_INSTANCES )
    {
        EMLogError("Slot-id[%d] is out of range", static_cast<uint32_t>(slotId));
        return false;
    }

    return true;
}

void BbuManager::checkRecvImsi()
{
    bool hasRcvImsi = false;
    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].BbuIsRegisted() )
        {
            if( bbuCtrls_[i].isRecvImsi() )
            {
                EMLogInfo("BBU[%d] have recv imsi in two hour so break\n", bbuCtrls_[i].instanceData_.getSlotId());
                hasRcvImsi = true;
                break; 
            }
            else
            {
                EMLogInfo("BBU[%d] have not recv imsi in two hour\n", bbuCtrls_[i].instanceData_.getSlotId());
            }
        }
    }


    for(uint32_t i=0; i<MAX_BBU_INSTANCES; i++)
    {
        if( bbuCtrls_[i].BbuIsRegisted() && bbuCtrls_[i].instanceData_.isActive() )
        {
            if( !bbuCtrls_[i].isRecvImsi() && hasRcvImsi && 
                (EutranConfigDataPtr->getTxPowerDb(bbuCtrls_[i].instanceData_.getSlotId()) != 127 ) &&
                (EutranConfigDataPtr->getWorkingMode(bbuCtrls_[i].instanceData_.getSlotId()) ==  PARA_VALUE_WOKRING_TYPE_NORMAL) )
            {
                EMLogWarning("BBU[%d] have not recv imsi in two hour make sure system work normal so reboot\n", bbuCtrls_[i].instanceData_.getSlotId());
                std::string desc = "have not recv imsi in two hour";
                bbuCtrls_[i].handleCtrlPA(false, BbuCtrl::REBOOT);
                reportCannotRecvImsi(bbuCtrls_[i].instanceData_.getSlotId());          
            }
            else
            {
                bbuCtrls_[i].setRecvImsi(false);
            }
        }
    }
    EutranTimerPtr->queue(checkRecvImsiTimer_, &checkRecvImsiHandler_);    

}

void BbuManager::reportCannotRecvImsi(uint8_t slotId)
{
    EMLogWarning("Report BBU[%d] can not recv imsi", slotId);
    std::vector < WrapperCmdPara > responseParas;
    responseParas.push_back(WrapperCmdPara(PARA_TYPE_EUTRAN_BBU_SLOT_ID, slotId));
    EutranMgrPtr->reportInfo(CMD_EVT_EUTRAN_NOT_RECV_IMSI, responseParas);

}

void BbuManager::setLocationImsi(std::vector<std::string>& imsi)
{
    locaionTargetImsi_ = imsi;
}


void BbuManager::getLocationImsi(std::vector<std::string>& imsi)
{
    imsi = locaionTargetImsi_;
}

void BbuManager::setLocationEnable(LteDuplexMode mode, bool enable)
{
	locationEnable[mode] = enable;
}

bool BbuManager::getLocationEnable(LteDuplexMode mode)
{	
	return locationEnable[mode];
}

void BbuManager::setLocationMode(bool isLocationMode)
{
	isLocationMode_ = isLocationMode;
}

bool BbuManager::isLocationMode()
{
	return isLocationMode_;
}

void BbuManager::reportBbuLost(uint8_t slotId)
{
    EMLogWarning("Report BBU[%d] lost", slotId);
    std::vector < WrapperCmdPara > responseParas;
    responseParas.push_back(WrapperCmdPara(PARA_TYPE_EUTRAN_BBU_SLOT_ID, slotId));
    EutranMgrPtr->reportInfo(CMD_EVT_EUTRAN_BBU_LOST, responseParas);


}
